package com.dycong.common.web;

import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.method.annotation.ExceptionHandlerMethodResolver;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * todo SPI 注入，定义 Dubbo bean 时，引用 Filter
 * @author dycong
 * @date 2019/6/22 19:40
 */
@Log4j2
@ControllerAdvice
@Activate(
        group = {"provider", "consumer"},
        order = -9000
)
public class DubboExceptionHandlerFilter implements Filter {

    private static final JSONResult<String> RSP = new JSONResult<String>(-2, "参数错误", null);

    // TODO: 2019/6/22 在 ControllerAdvice 中定义多个@ExceptionHandler 处理不同的异常 ，Order 对 ExceptionHandler 顺序无效，ExceptionHandlerMethodResolver
    //  会对异常的匹配程度(一层层递归getSuperclass equals 来计算depth)进行排序，取匹配度最高的resolveMethod处理异常

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        log.debug("BizExceptionFilter:{},{}", invoker.getInterface(),
                Arrays.toString(invocation.getArguments()));

        Result result = invoker.invoke(invocation);

        Object realResult = result.getValue();

        if (result.hasException()) {
            try {
                ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(this.getClass());
                Exception exception = (Exception) result.getException();
                Method method = resolver.resolveMethod(exception);
                if (null == method){
                    // TODO: 2019/6/22 没有定义可以处理该异常的 Handler
                    return result;
                }
                realResult = method.invoke(this, exception);

                return new RpcResult(realResult);
            } catch (Throwable e) {
                log.error("Exception handler error. Caused Exception:{}", result.getException());
            }
        }

        return new RpcResult(RSP);
    }

    @ExceptionHandler(value = NullPointerException.class)
    public Object handleIOException(NullPointerException e) {
        log.info("Catch exception", e);
        String exceptionName = e.getClass().getName();

        return RSP;
    }

    @ExceptionHandler(value = IndexOutOfBoundsException.class)
    public Object handleIOException(IndexOutOfBoundsException e) {
        log.info("Catch exception", e);
        String exceptionName = e.getClass().getName();

        return RSP;
    }


}
